package cn.tju.yanbo.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cn.tju.yanbo.R;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.Log;

public class AppUtils {
    
    public static Calendar CALENDAR_INSTANCE = Calendar.getInstance();
    public static Typeface APP_FONT = null;
    public static final DisplayMetrics SCREEN_METRICS =  new DisplayMetrics();
    private static final SimpleDateFormat sdf = new SimpleDateFormat();
    private static final Pattern LUNAR_CALENDAR_PATTERN = Pattern.compile("([^x00-xff]+年)([^x00-xff]+月)([^x00-xff]+)");
    
    public static Typeface font(Typeface...font) {
        if(font.length==1 && APP_FONT==null)
            APP_FONT = font[0];
        return APP_FONT;
    }
    
    public static Drawable createDrawable(Resources res, int resId) {
        Bitmap img = BitmapFactory.decodeResource(res, resId);
        return new BitmapDrawable(img);
    }
    
    public static List<String> load(String fileName) throws IOException {
        InputStream is = AppUtils.class.getResourceAsStream(fileName);
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        
        List<String> strs = new ArrayList<String>();
        String line = null;
        while((line=br.readLine())!=null) {
            if(!empty(line)) strs.add(line);
        }
        return strs;
    }
    
    public static boolean empty(String str) {
        if(str==null || "".equals(str.trim())) {
            return true;
        }
        return false;
    }
    
    public static String format(String format, Date d) {
        sdf.applyPattern(format);
        return sdf.format(d);
    }
    
    public static String format(String format, long timeMillis) {
        sdf.applyPattern(format);
        return sdf.format(new Date(timeMillis));
    }
    
    public static String [] ymd(String lc) {
        String [] ymd = new String[3];
        Matcher m = LUNAR_CALENDAR_PATTERN.matcher(lc);
        if(m.find()) {
            ymd[0] = m.group(1);
            ymd[1] = m.group(2);
            ymd[2] = m.group(3);
            return ymd;
        }
        throw new IllegalArgumentException("lunar calendar string "+lc+" format is illegal.");
    }
    
    public static double[] revovle(double p[], double angle) {
        double [] p1 = new double[]{p[0], p[1], 1};
        
        double [][] rotateMatrix = new double[][]{
                {Math.cos(angle), Math.sin(angle), 0}, 
                {-Math.sin(angle), Math.cos(angle), 0},
                {0, 0, 1}
        };
        double [] p2 = multiply(rotateMatrix, p1);
        return new double[]{p2[0], p2[1]};
    }
    
    public static double [] multiply(double matrix[][], double v[]) {
        double [] rv = new double[matrix.length];
        double pv = 0;
        for(int i=0; i<matrix.length; i++) {
            pv = 0;
            for(int j=0; j<v.length; j++) {
                pv += matrix[j][i]*v[j];
            }
            rv[i] = pv;
        }
        return rv;
    }
    
    public static double includedAngle(double [] v1, double [] v2) {
        double l1 = Math.sqrt((double)(v1[0]*v1[0]+v2[1]*v2[1]));
        double l2 = Math.sqrt((double)v2[0]*v2[0]+v2[1]*v2[1]);
        double dp = (double)v1[0]*v2[0]+v1[1]*v2[1];
        
        return Math.acos(dp/(l1*l2));
    }
    
    public static double degree(double angle) {
        return (int) (angle*180/Math.PI);
    }
    public static double angle(double degree) {
        return degree*Math.PI/180;
    }
    
    public static double length(Point p1, Point p2) {
        double vx = p1.x-p2.x;
        double vy = p1.y-p2.y;
        return Math.sqrt(vx*vx + vy*vy);
    }
    
    public static Rect layout(Point centroid, double radius, double degree, Rect bound) {
        double viewOriginX = centroid.x + radius*Math.sin(degree);
        double viewOriginY = centroid.y + radius*Math.cos(degree);
        int translateX = (bound.right-bound.left)/2;
        int translateY = (bound.bottom-bound.top)/2;
        return new Rect((int)(viewOriginX-translateX), (int)(viewOriginY-translateY), (int)(viewOriginX+translateX), (int)(viewOriginY+translateY));
    }
    
    public static Point position(Point centroid, double radius, double degree, float width, float height) {
        float viewOriginX = centroid.x + (float)(radius*Math.sin(degree));
        float viewOriginY = centroid.y + (float)(radius*Math.cos(degree));
        float translateX = width/2;
        float translateY = height/2;
        return new Point(Math.round(viewOriginX-translateX), Math.round(viewOriginY-translateY));
    }
    
    public static String toString(Object o) {
        return o==null?null:o.toString();
    }
    
    public static int getPointContainsRing(Point p, Point centroid, int ... radius) {
        double length = AppUtils.length(p, centroid);
        Log.i("gui", "length="+length);
        for(int i=0; i<radius.length; i++) {
            if(length<radius[i]) {
                return i;
            }
        }
        return -1;
    }
    
    public static boolean isPointInCompass(Point p, Point centroid, int radius) {
        double length = AppUtils.length(p, centroid);
        return length<radius;
    }

    
    public static Rect revolveRect(Rect bounds, Point centroid, double degree) {
        double [] leftUpPoint = revolve(bounds, centroid, degree);
        int left = (int)Math.round(leftUpPoint[0]);
        int top = (int)Math.round(leftUpPoint[1]);
        int width = bounds.right-bounds.left;
        int height = bounds.bottom-bounds.top;
        return new Rect(left, top, left+width, top+height);
    }
    
    public static double [] revolve(Rect bounds, Point centroid, double degree) {
        double revolvePointX = ((double)(bounds.left+bounds.right))/2;
        double revolvePointY = ((double)(bounds.top+bounds.bottom))/2;
        double [] point2revovle = new double[]{revolvePointX, revolvePointY};
        double [] cpoint = new double[]{centroid.x, centroid.y};
        double [] revolvedPoint = revolve(point2revovle, cpoint, degree);

        if(revolvedPoint[1]<=AppConfig.DATE_COMPASS_CENTROID.y) {
            revolvedPoint = AppUtils.symmetry(revolvedPoint, new double[]{centroid.x, centroid.y});
        }
        
        double dx = revolvedPoint[0]-revolvePointX;
        double dy = revolvedPoint[1]-revolvePointY;
        
        return new double[]{bounds.left+dx, bounds.top+dy};
    }
    
    public static double [] revolve(double [] p, double [] centroid, double degree) {
        double angle = -AppUtils.angle(degree);
        double [] translatedPoint = new double[]{p[0]-centroid[0], p[1]-centroid[1]};
        double [] revovledPointInTranslatedAxes = AppUtils.revovle(translatedPoint, angle);
        double [] revolvedPoint = new double[]{revovledPointInTranslatedAxes[0]+centroid[0], revovledPointInTranslatedAxes[1]+centroid[1]};

        return revolvedPoint;
    }
    
    public static Point symmetry(Point p, Point centroid) {
        return new Point(2*centroid.x-p.x, 2*centroid.y-p.y);
    }
    public static double [] symmetry(double [] p, double [] centroid) {
        return new double[]{2*centroid[0]-p[0], 2*centroid[1]-p[1]};
    }
    
    public static String parse(String tag) {
        tag = tag.replaceFirst("[\\S]*\\s+", "");
        tag = tag.replaceFirst("_[a-zA-Z]+_?", "_left_");
        tag = tag.concat("1");
        return tag.replaceFirst("[\\d]+", "1");
    }
    
    public static int getMonthLastDay(int year, int month) {
        CALENDAR_INSTANCE.set(Calendar.YEAR, year);
        CALENDAR_INSTANCE.set(Calendar.MONTH, month+1);
        CALENDAR_INSTANCE.set(Calendar.DAY_OF_MONTH, 1);
        CALENDAR_INSTANCE.roll(Calendar.DAY_OF_MONTH, -1);
        
        return CALENDAR_INSTANCE.get(Calendar.DAY_OF_MONTH);
    }
    
    public static int[] randomNDays(long seeds, int n, int monthLastDay) {
        int [] randomDays = new int[n];
        Random random = new Random(seeds);
        
        for(int i=0; i<n; i++) {
            randomDays[i] = Math.abs(random.nextInt())%monthLastDay+1;
            for(int j=0; j<i; j++) {
                if(randomDays[i]==randomDays[j]) {
                    i--;
                    break;
                }
            }
        }
        Arrays.sort(randomDays);
        return randomDays;
    }
    
    public static int width(String tag) {
        if(tag.indexOf("compass_day_ring")>=0) {
            return 20;
        } else if(tag.indexOf("compass_month_ring")>=0) {
            return 16;
        } else {
            return -1;
        }
    }
    
    public static String lunarHour(int hour) {
        switch(hour) {
            case 1 : case 2 : return "子时";
            case 3 : case 4 : return "丑时";
            case 5 : case 6 : return "寅时";
            case 7 : case 8 : return "卯时";
            case 9 : case 10 : return "辰时";
            case 11 : case 12 : return "巳时";
            case 13 : case 14 : return "午时";
            case 15 : case 16 : return "未时";
            case 17 : case 18 : return "申时";
            case 19 : case 20 : return "酉时";
            case 21 : case 22 : return "戌时";
            case 23 : case 0 : return "亥时";
            default : return "";
        }
    }
    
    public static int sinarHour(String hour) {
        if(hour.equals("子时")) return 1;
        if(hour.equals("丑时")) return 3;
        if(hour.equals("寅时")) return 5;
        if(hour.equals("卯时")) return 7;
        if(hour.equals("辰时")) return 9;
        if(hour.equals("巳时")) return 11;
        if(hour.equals("午时")) return 13;
        if(hour.equals("申时")) return 15;
        if(hour.equals("未时")) return 17;
        if(hour.equals("酉时")) return 19;
        if(hour.equals("戌时")) return 21;
        if(hour.equals("亥时")) return 23;
        return 0;
    }
    
    public static int touchOnWhichBounds(Point p, Rect ... boundsList) {
        for(int i=0; i<boundsList.length; i++) {
            if(boundsList[i].contains(p.x, p.y)) return i;
        }
        return -1;
    }
    
    public static String getDrawableKey(String tag) {
        tag = tag.trim();
        tag = "yi_"+tag;
        return tag;
    }
    
    public static boolean isChoosed(String tag) {
        if("not_choosed".equals(tag)) return true;
        else return false;
    }
}
